package com.bonc.apicreator.swagger.utils;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.bonc.apicreator.constant.BaseConstant;
import com.bonc.apicreator.entity.RestApi;
import com.bonc.apicreator.entity.RestApiRequest;
import com.bonc.apicreator.entity.RestApiResponse;
import com.bonc.apicreator.swagger.action.SwaggerConstant;
import com.bonc.apicreator.swagger.models.NestProperty;
import com.bonc.apicreator.swagger.models.OperationForSort;
import com.bonc.apicreator.utils.JsonUtils;
import com.fasterxml.jackson.core.type.TypeReference;

import io.swagger.models.Path;
import io.swagger.models.Response;
import io.swagger.models.parameters.BodyParameter;
import io.swagger.models.parameters.CookieParameter;
import io.swagger.models.parameters.FormParameter;
import io.swagger.models.parameters.HeaderParameter;
import io.swagger.models.parameters.Parameter;
import io.swagger.models.parameters.PathParameter;
import io.swagger.models.parameters.QueryParameter;
import io.swagger.models.properties.ArrayProperty;
import io.swagger.models.properties.ObjectProperty;
import io.swagger.models.properties.Property;
import io.swagger.models.properties.StringProperty;
import io.swagger.parser.SwaggerCompatConverter;


/**
 * swagger工具类
 *
 * @author liuchang
 * @version 2016年8月21日
 * @see BuildUtil
 * @since
 */

public class BuildUtil {

    SwaggerCompatConverter converter = new SwaggerCompatConverter();

    /**
     * Description: 组装方法，参数请求类型
     * 
     * @param path
     * @param api
     * @param operation
     * @return Path
     * @see
     */
    public static Path buildPath(Path path, RestApi api, OperationForSort operation) {
        if (path == null) {

            path = new Path();
        }

        switch (api.getRequestType()) {
            case SwaggerConstant.REQUESTTYPE_GET:
                path.setGet(operation);
                break;

            case SwaggerConstant.REQUESTTYPE_POST:
                path.setPost(operation);
                break;

            case SwaggerConstant.REQUESTTYPE_DELETE:
                path.setDelete(operation);
                break;

            case SwaggerConstant.REQUESTTYPE_PUT:
                path.setPut(operation);
                break;
            case SwaggerConstant.REQUESTTYPE_HEADER:
                path.setHead(operation);
                break;
            case SwaggerConstant.REQUESTTYPE_PATCH:

                path.setPatch(operation);
                break;
            default:
                break;

        }

        return path;
    }

    /**
     * Description: 创建树结构
     * 
     * @param childList
     * @return RestApiResponse
     * @see
     */
    public static RestApiResponse buildTreeNode(String childList) {
        RestApiResponse tree = new RestApiResponse();
        List<RestApiResponse> rootList = new ArrayList<RestApiResponse>();
        if (!StringUtils.isEmpty(childList)) {
            List<RestApiResponse> nodeList = JsonUtils.toObject(childList,
                new TypeReference<List<RestApiResponse>>() {});

            Map<String, RestApiResponse> nodeMap = new HashMap<String, RestApiResponse>();

            for (RestApiResponse nodeInfo : nodeList) {
                nodeMap.put(nodeInfo.getNodeId(), nodeInfo);
                if (StringUtils.isEmpty(nodeInfo.getParentId())) {
                    rootList.add(nodeInfo);
                }
                else {
                    nodeMap.get(nodeInfo.getParentId()).getChildren().add(nodeInfo);
                }

            }

        }

        tree.setChildren(rootList);

        return tree;
    }

    /**
     * Description: 组装节点信息
     * 
     * @param response
     * @return RestApiResponse
     * @see
     */

    public static RestApiResponse buildTreeNode(RestApiResponse response) {
        RestApiResponse tree = buildTreeNode(response.getChildrenList());

        tree.setType(response.getType());
        tree.setCode(response.getCode());
        tree.setDescription(response.getDescription());

        return tree;
    }

    /**
     * Description: 操作组装
     * 
     * @param api
     * @param apiRequests
     * @param apiResponses
     * @return Operation
     * @see
     */
    public static OperationForSort buildOperation(RestApi api, List<RestApiRequest> apiRequests,
                                                  List<RestApiResponse> apiResponses) {
        OperationForSort operation = new OperationForSort();
        operation.setSort(api.getSort());
        operation.setConsumes(buildConsumeList(api.getRequestFormat()));
        operation.setProduces(buildProduceList(api.getResponseFormat()));
        operation.setSummary(api.getName());
        operation.setDescription(api.getDescription());
        operation.setTags(parseTags(api));

        operation.setParameters(parseParameter(apiRequests));
        operation.setResponses(parseResponse(apiResponses, api));
        return operation;
    }

    /**
     * Description:请求位置组装
     * 
     * @param apiRequests
     * @return List<Parameter>
     * @see
     */
    private static List<Parameter> parseParameter(List<RestApiRequest> apiRequests) {
        List<Parameter> result = new ArrayList<Parameter>();
        Parameter parameter = null;

        for (RestApiRequest apiRequest : apiRequests) {

            switch (apiRequest.getLocation()) {
                case SwaggerConstant.LOCATION_BODY:
                    parameter = parseBodyParameter(apiRequest);
                    break;
                case SwaggerConstant.LOCATION_COOKIE:
                    parameter = parseCookieParameter(apiRequest);
                    break;
                case SwaggerConstant.LOCATION_FORMDATA:
                    parameter = parseFormDataParameter(apiRequest);
                    break;
                case SwaggerConstant.LOCATION_HEADER:
                    parameter = parseHeaderParameter(apiRequest);
                    break;
                case SwaggerConstant.LOCATION_PATH:
                    parameter = parsePathParameter(apiRequest);
                    break;
                case SwaggerConstant.LOCATION_QUERY:
                    parameter = parseQueryParameter(apiRequest);
                    break;
                default:
                    break;

            }
            result.add(parameter);
        }
        return result;
    }

    /**
     * Description: body类型请求参数
     * 
     * @param apiRequest
     * @return Parameter
     * @see
     */
    private static Parameter parseBodyParameter(RestApiRequest apiRequest) {

        BodyParameter bodyParameter = new BodyParameter();
        bodyParameter.setName(apiRequest.getCode());
        bodyParameter.setRequired(changeString(apiRequest));

        bodyParameter.setDescription(apiRequest.getDescription());
        return bodyParameter;
    }

    /**
     * Description:cookie类型请求参数
     * 
     * @param apiRequest
     * @return Parameter
     * @see
     */
    private static Parameter parseCookieParameter(RestApiRequest apiRequest) {
        CookieParameter cookieParameter = new CookieParameter();
        cookieParameter.setDescription(apiRequest.getDescription());
        cookieParameter.setFormat(apiRequest.getLocation());
        cookieParameter.setType(change(apiRequest));
        cookieParameter.setName(apiRequest.getCode());

        return cookieParameter;
    }

    /**
     * Description:formData类型请求参数
     * 
     * @param apiRequest
     * @return Parameter
     * @see
     */
    private static Parameter parseFormDataParameter(RestApiRequest apiRequest) {
        FormParameter formParameter = new FormParameter();
        formParameter.setDescription(apiRequest.getDescription());
        formParameter.setFormat(apiRequest.getLocation());
        formParameter.setRequired(changeString(apiRequest));
        formParameter.setType(change(apiRequest));
        formParameter.setName(apiRequest.getCode());

        return formParameter;
    }

    /**
     * Description:header类型请求参数
     * 
     * @param apiRequest
     * @return Parameter
     * @see
     */
    private static Parameter parseHeaderParameter(RestApiRequest apiRequest) {
        HeaderParameter headerParameter = new HeaderParameter();
        headerParameter.setDescription(apiRequest.getDescription());
        headerParameter.setFormat(apiRequest.getLocation());
        headerParameter.setRequired(changeString(apiRequest));
        headerParameter.setType(change(apiRequest));
        headerParameter.setName(apiRequest.getCode());

        return headerParameter;
    }

    /**
     * Description: path类型的请求参数
     * 
     * @param apiRequest
     * @return Parameter
     * @see
     */
    private static Parameter parsePathParameter(RestApiRequest apiRequest) {
        PathParameter pathParameter = new PathParameter();
        pathParameter.setDescription(apiRequest.getDescription());
        pathParameter.setFormat(apiRequest.getLocation());
        pathParameter.setRequired(changeString(apiRequest));
        pathParameter.setType(change(apiRequest));
        pathParameter.setName(apiRequest.getCode());

        return pathParameter;
    }

    /**
     * Description: query类型的请求参数
     * 
     * @param apiRequest
     * @return Parameter
     * @see
     */
    private static Parameter parseQueryParameter(RestApiRequest apiRequest) {

        QueryParameter queryParameter = new QueryParameter();

        queryParameter.setDescription(apiRequest.getDescription());
        queryParameter.setFormat(apiRequest.getLocation());
        queryParameter.setRequired(changeString(apiRequest));
        queryParameter.setType(change(apiRequest));
        queryParameter.setName(apiRequest.getCode());

        return queryParameter;
    }

    /**
     * Description:响应的组装
     * 
     * @param apiReponses
     * @return Map<String,Response>
     * @see
     */
    private static Map<String, Response> parseResponse(List<RestApiResponse> apiReponses,
                                                       RestApi api) {
        Map<String, Response> result = new HashMap<String, Response>();
        Property property = buildProperty(apiReponses, api);
        Response response = new Response();
        response.setSchema(property);
        result.put(SwaggerConstant.RESPONSE_NORMAL, response);
        return result;
    }

    /**
     * Description:组建properties
     * 
     * @param response
     * @return Property
     * @see
     */

    private static Property buildProperty(List<RestApiResponse> apiReponses, RestApi api) {

        Map<String, Property> map = new HashMap<String, Property>();
        String responseDataType = api.getResponseDataType();

        for (RestApiResponse restApiResponse : apiReponses) {
            String type = restApiResponse.getType();
            if (BaseConstant.TYPE_OBJECT.equals(type) || BaseConstant.TYPE_ARRAY.equals(type)) {

                restApiResponse = buildTreeNode(restApiResponse);
                Property objProperty = buildTreeProperty(restApiResponse);
                map.put(restApiResponse.getCode(), objProperty);
            }
            else {
                StringProperty normalProperty = new StringProperty();
                normalProperty.setDescription(restApiResponse.getDescription());
                map.put(restApiResponse.getCode(), normalProperty);
            }
        }
        if (SwaggerConstant.APIRESPONSE_LIST.equals(responseDataType)) {
            ArrayProperty array = new ArrayProperty();
            NestProperty nestProperty = new NestProperty();

            nestProperty.setProperties(map);
            array.items(nestProperty);

            return array;
        }

        NestProperty nestProperty = new NestProperty();
        nestProperty.setProperties(map);

        return nestProperty;

    }

    /**
     * Description:建立property的树结构
     * 
     * @param apiResponse
     * @return Property
     * @see
     */

    private static Property buildTreeProperty(RestApiResponse apiResponse) {

        Property property = null;
        String type = apiResponse.getType();
        switch (type) {
            case BaseConstant.TYPE_OBJECT:
                property = parseObjectProperty(apiResponse);
                break;

            case BaseConstant.TYPE_ARRAY:
                property = parseArrayProperty(apiResponse);
                break;

            default:
                property = parseSimpleProperty(apiResponse);
                break;
        }

        return property;
    }

    /**
     * Description: 组装数组
     * 
     * @param apiResponse
     * @return Property
     * @see
     */
    private static Property parseArrayProperty(RestApiResponse apiResponse) {

        ArrayProperty property = new ArrayProperty();
        property.setDescription(apiResponse.getDescription());
        property.setName(apiResponse.getCode());
        property.setType(apiResponse.getType());

        List<RestApiResponse> children = apiResponse.getChildren();
        if (!CollectionUtils.isEmpty(children)) {
            NestProperty nestProperty = new NestProperty();
            nestProperty.setTitle(apiResponse.getCode());
            for (RestApiResponse sub : children) {
                // 子节点不为空给子节点设置树结构
                nestProperty.getProperties().put(sub.getCode(), buildTreeProperty(sub));
            }
            property.setItems(nestProperty);
        }
        else {
            // 子节点为空显示空对象
            property.setItems(new ObjectProperty());
        }
        return property;
    }

    /**
     * Description:组装对象
     * 
     * @param apiResponse
     * @return Property
     * @see
     */
    private static Property parseObjectProperty(RestApiResponse apiResponse) {

        NestProperty property = new NestProperty();
        property.setDescription(apiResponse.getDescription());
        property.setName(apiResponse.getCode());
        property.setType(apiResponse.getType());
        property.setTitle(apiResponse.getCode());

        List<RestApiResponse> children = apiResponse.getChildren();
        // 组装property的子节点
        if (!CollectionUtils.isEmpty(children)) {
            for (RestApiResponse sub : children) {
                property.getProperties().put(sub.getCode(), buildTreeProperty(sub));
            }
        }

        return property;
    }

    /**
     * Description:组装简单类型
     * 
     * @param apiResponse
     * @return Property
     * @see
     */
    private static Property parseSimpleProperty(RestApiResponse apiResponse) {
        Map<String, Property> map = new HashMap<String, Property>();
        StringProperty stringProperty = new StringProperty();
        stringProperty.setDescription(apiResponse.getDescription());
        map.put(apiResponse.getCode(), stringProperty);
        NestProperty nestProperty = new NestProperty();
        nestProperty.setProperties(map);
        return nestProperty;
    }

    /**
     * Description:分类的组装
     * 
     * @param api
     * @return List<String>
     * @see
     */
    private static List<String> parseTags(RestApi api) {
        List<String> result = new ArrayList<String>();
        String apiName = "api";
        String moduleName = api.getModuleName();
        if (!StringUtils.isEmpty(moduleName)) {
            result.add(moduleName);
        }
        else {
            result.add(apiName);
        }
        return result;

    }

    /**
     * Description: 改变type的表现形式
     * 
     * @param apiRequest
     * @return String
     * @see
     */
    private static String change(RestApiRequest apiRequest) {
        String type = apiRequest.getType();

        if (type.equals(SwaggerConstant.APIREQUEST_STRING)) {
            type = "string";

        }
        if (type.equals(SwaggerConstant.APIREQUEST_INT)) {
            type = "integer";
        }
        if (type.equals(SwaggerConstant.APIREQUEST_LONG)) {
            type = "integer";
        }
        if (type.equals(SwaggerConstant.APIREQUEST_DOUBLE)) {
            type = "number";
        }
        if (type.equals(SwaggerConstant.APIREQUEST_FLOAT)) {
            type = "number";
        }
        if (type.equals(SwaggerConstant.APIREQUEST_DECIMAL)) {
            type = "number";
        }
        return type;
    }

    /**
     * Description: changeString
     * 
     * @param apiRequest
     * @return boolean
     * @see
     */

    private static boolean changeString(RestApiRequest apiRequest) {
        String isMust = apiRequest.getIsMust();
        boolean a = false;
        if (isMust.equals("true")) {
            a = true;
        }
        return a;

    }
    /*  *//**
           * Description: scheme的解析
           * 
           * @param scheme
           * @return List<Scheme>
           * @see
           *//*
             * public static List<Scheme> buildSchemeList(String scheme) { List<Scheme> result =
             * new ArrayList<Scheme>(); List<String> list = parseList(scheme); for (String temp :
             * list) { result.add(Scheme.valueOf(temp)); } return result; }
             */

    /**
     * Description:请求方式
     * 
     * @param consume
     * @return List<String>
     * @see
     */
    public static List<String> buildConsumeList(String consume) {
        return parseList(consume);
    }

    /**
     * Description:响应方式
     * 
     * @param produce
     * @return List<String>
     * @see
     */
    public static List<String> buildProduceList(String produce) {
        return parseList(produce);
    }

    /**
     * Description:list的转换
     * 
     * @param value
     * @return List<String>
     * @see
     */
    public static List<String> parseList(String value) {
        List<String> result = new ArrayList<String>();
        if (StringUtils.isEmpty(value)) {
            return result;
        }

        String[] valueArray = value.split(",");
        for (String temp : valueArray) {
            result.add(temp);
        }

        return result;
    }
}